// File provided for Microsoft Shared Source.
// Copyright (c) Microsoft Corporation. All rights reserved.

#pragma once

#ifndef STRICT
#define STRICT
#endif

#define WINVER _WIN32_WINNT_LONGHORN        // Change this to the appropriate value to target other versions of Windows.
#define _WIN32_WINNT _WIN32_WINNT_LONGHORN    // Change this to the appropriate value to target other versions of Windows.
#define _WIN32_WINDOWS _WIN32_WINNT_LONGHORN // Change this to the appropriate value to target Windows Me or later.

#define _WIN32_IE _WIN32_IE_IE70    // Change this to the appropriate value to target other versions of IE.

#define NTDDI_VERSION NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT_LONGHORN)

#define _ATL_APARTMENT_THREADED
#define _ATL_NO_AUTOMATIC_NAMESPACE

#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS    // some CString constructors will be explicit

#define _ATL_DEBUG
#define _ATL_DEBUG_QI

#define STRICT_TYPED_ITEMIDS    // IDList type-saftey

#include <atlbase.h>
#include <atlcom.h>
#include <atlcoll.h>
#include <shlobj.h>
#include <strsafe.h>

#include <shlGuid.h>
#include <shobjidl.h>
//#include <ntquery.h>
#include <objbase.h>
#include <propkey.h>
#include <propvarutil.h>

#include <Wbemidl.h>
#include <wmiutils.h>
#pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "propsys.lib")

using namespace ATL;

#pragma hdrstop
#pragma warning (disable: 4100)
#include "resource.h"

#ifndef IFACEMETHODIMP_
#define IFACEMETHODIMP_(type) virtual type STDMETHODCALLTYPE
#endif

#ifndef IFACEMETHODIMP
#define IFACEMETHODIMP IFACEMETHODIMP_(HRESULT)
#endif

#ifndef IID_PPV_ARGS
#define IID_PPV_ARGS(ppI) __uuidof(**ppI), ((void**)ppI)
#endif

inline void Trace(PCWSTR pszFormat, ...)
{
    WCHAR szTrace[2000];
    va_list valist;
    va_start(valist, pszFormat);

    StringCchVPrintf(szTrace, ARRAYSIZE(szTrace), pszFormat, valist);

    va_end(valist);

    OutputDebugString(szTrace);
}

#define QI_ENTRY_EX(className, baseClass) \
    if (riid == __uuidof(className)) \
    { \
        baseClass *pByWayOfType = this; \
        className *pBaseType = pByWayOfType; \
        *ppv = (void*)pBaseType; \
        __if_exists(AddRef) \
        { \
            AddRef(); \
        } \
        return S_OK; \
    } else {}

template<>
class CElementTraits< PROPERTYKEY > :
	public CElementTraitsBase< PROPERTYKEY >
{
public:
	static ULONG Hash( INARGTYPE pkey )
	{
        return CElementTraits<GUID>::Hash(pkey.fmtid) ^ CElementTraits<DWORD>::Hash(pkey.pid);
	}

	static bool CompareElements( INARGTYPE element1, INARGTYPE element2 )
	{
        return CElementTraits<GUID>::CompareElements(element1.fmtid, element2.fmtid)
            && CElementTraits<DWORD>::CompareElements(element1.pid, element2.pid);
	}

	static int CompareElementsOrdered( INARGTYPE element1, INARGTYPE element2 )
	{
        int iCmp = CElementTraits<GUID>::CompareElementsOrdered(element1.fmtid, element2.fmtid);
        if (iCmp == 0)
        {
            iCmp = CElementTraits<DWORD>::CompareElementsOrdered(element1.pid, element2.pid);
        }
		return iCmp;
	}
};

#define QI_ENTRY(className) QI_ENTRY_EX(className, className)

extern LONG g_cDllLock;
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)

#define TRACEFNENTER() if (FALSE) Trace(L"::> %s\r\n", WIDEN(__FUNCTION__))
#define TRACEFNENTER_IID(iid) if (FALSE && ShouldTraceIID(riid)) Trace(L"::> %s IID %s\r\n", WIDEN(__FUNCTION__), SmartStringFromIID(iid))
#define TRACEFNEXIT() if (FAILED(hr)) { Trace(L"::< %s (0x%x)\r\n", WIDEN(__FUNCTION__), hr); } else {}
#define TRACEFNEXIT_IID(iid) if (FAILED(hr) && ShouldTraceIID(riid)) { Trace(L"::< %s (0x%x) IID %s\r\n", WIDEN(__FUNCTION__), hr, SmartStringFromIID(iid)); } else {}
#define TRACEFNEXIT_PKEY(pkey) if (FAILED(hr) && ShouldTracePKEY(pkey)) { Trace(L"::< %s (0x%x) PKEY %s\r\n", WIDEN(__FUNCTION__), hr, SmartStringFromPKEY(pkey)); } else {}

PCWSTR SmartStringFromIID(REFIID riid);
PCWSTR SmartStringFromPKEY(REFPROPERTYKEY pkey);
BOOL ShouldTraceIID(REFIID riid);
BOOL ShouldTracePKEY(REFPROPERTYKEY riid);

// use for extracting a comparison value from return value of IShellFolder::CompareIDs()
__inline short ShortFromResult(HRESULT hr)
{
    return (short)HRESULT_CODE(hr);
}

inline HRESULT CloneIDList(PCUIDLIST_RELATIVE pidl, __deref_out PIDLIST_RELATIVE *ppidlOut)
{
    HRESULT hr = E_INVALIDARG;
    if (pidl)
    {
        *ppidlOut = ILClone(pidl);
        hr = *ppidlOut ? S_OK : E_OUTOFMEMORY;
    }
    return hr;
}

inline HRESULT CloneFullIDList(PCUIDLIST_ABSOLUTE pidl, __deref_out PIDLIST_ABSOLUTE *ppidlOut)
{
    return CloneIDList(pidl, reinterpret_cast<PIDLIST_RELATIVE *>(ppidlOut));
}

inline HRESULT CloneChildIDList(PCITEMID_CHILD pidl, __deref_out PITEMID_CHILD *ppidlOut)
{
    *ppidlOut = ILCloneChild(pidl);
    return *ppidlOut ? S_OK : E_OUTOFMEMORY;
}

inline HRESULT CombineIDLists(PCIDLIST_ABSOLUTE pidl1, PCUIDLIST_RELATIVE pidl2, __out PIDLIST_ABSOLUTE *ppidlOut)
{
    *ppidlOut = ILCombine(pidl1, pidl2);
    return *ppidlOut ? S_OK : E_OUTOFMEMORY;
}

inline HRESULT CloneFirstIDList(PCUIDLIST_RELATIVE pidl, __deref_out PITEMID_CHILD *ppidl)
{
    *ppidl = ILCloneFirst(pidl);
    return *ppidl ? S_OK : E_OUTOFMEMORY;
}

__inline HRESULT ResultFromShort(int i)
{ 
    return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (USHORT)(i));
}

// use to creating an HRESULT to be returned from IShellFolder::CompareIDs() from a comparison value
__inline HRESULT CompareResultFromInt(int i)
{
    // Preserves the value's sign when casting to short
    return ResultFromShort((USHORT)(i < 0 ? -1 : (i > 0 ? 1 : 0)));
}

